from fastapi import FastAPI, APIRouter, HTTPException, Request, Depends
from peewee import OperationalError, Model
from .config import redis, secret, resps, models
from redis import Redis # 导入redis 模块
import jwt
from typing import Annotated, Dict, List
from fastapi.security import OAuth2PasswordBearer
from contextlib import asynccontextmanager
from typing import AsyncGenerator
from starlette.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from .models.base import mysql_db, User

# 生命周期管理器
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    """管理应用生命周期"""
    try:
        # 启动时连接数据库
        mysql_db.connect()
        # 初始化表（生产环境建议使用迁移工具）
        ## mysql_db.create_tables([Order, OrderItem], safe=True)
        yield
    except OperationalError as e:
        raise RuntimeError(f"Database connection failed: {str(e)}")
    finally:
        # 关闭时释放连接
        if not mysql_db.is_closed():
            mysql_db.close()
            mysql_db.connect(True)

router = APIRouter(
    responses=resps
)

# 使用 lifespan 创建 FastAPI 实例
app = FastAPI(lifespan=lifespan)

@app.exception_handler(Exception)
async def exception_handler(request: Request, exc: Exception):
    code, msg = 201, '服务器内部错误'
    cla: str = exc.__class__.__name__
    match cla:
        case 'ExpiredSignatureError':
            code, msg = 401, 'Token expired'
        case 'CancelledError':
            code, msg = 401, '已取消'
        case 'OperationalError':
            code, msg = 501, '系统错误'
        case 'HTTPException':
            code, msg = exc.status_code, exc.detail
        case _:
            if cla.endswith('DoesNotExist'):
                code, msg = 404, models.get(cla[0:-12], '数据') + '不存在'

    return JSONResponse(
        status_code=200,
        content={'msg': msg, 'code': code, 'state': cla}
    )

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=200,
        content={'msg': exc.detail, 'code': exc.status_code}
    )

origins = [
    "http://115.190.79.161:8000",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

'''
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    # 请求前的处理逻辑
    response = await call_next(request)
    # 响应后的处理逻辑
    response_body = [chunk async for chunk in response.body_iterator]
    response.body_iterator = iterate_in_threadpool(iter(response_body))
    ## print(f"response_body={response_body[0]}")
    return response
'''

def success(data: Dict | List = {}, code: int = 200):
    return {
        'code': code,
        'msg': 'success',
        'data': data
    }

r = Redis(host=redis['host'], port=redis['port'], password=redis['password'], decode_responses=True)

async def auth(Authorization: Annotated[str, Depends(OAuth2PasswordBearer(tokenUrl="Authorization"))]):
    if Authorization is None:
        raise HTTPException(status_code=400, detail="X-Token header invalid")

    payload = jwt.decode(Authorization, secret['key'], algorithms=[secret['method']])
    uid = payload.get('id')

    if uid is None:
        raise HTTPException(status_code=400, detail="X-Token header invalid")
    model = User.get(User.id==uid)
    if model is None:
        raise HTTPException(status_code=400, detail="User not exist")
    else:
        app.state.user = model.__data__
    return True
### 识别身份
async def ident(Authorization: Annotated[str, Depends(OAuth2PasswordBearer(tokenUrl="Authorization", auto_error=False))]):
    if Authorization is None:
        return False
    try:
        payload = jwt.decode(Authorization, secret['key'], algorithms=[secret['method']])
        uid = payload.get('id')
    except:
        return False
    if uid is None:
        return False
    model = User.get(User.id==uid)
    if not model is None:
        app.state.user = model.__data__
    return True

def me(key: str = ''):
    if not hasattr(app.state, 'user') or not isinstance(app.state.user, Dict):
        return None
    elif key == '':
        return app.state.user
    elif app.state.user[key] is None:
        return None
    else:
        return app.state.user[key]

def depens(exc: bool = True):
    if exc:
        return [Depends(auth)]
    else:
        return [Depends(ident)]

